#include "OLED.h"
#include "oledfont.h"
#include "spi.h"

static unsigned char arr[128][8];

// ��SSD1106д��һ���ֽڡ�
// dat:Ҫд�������?/����
// cmd:����/������? 0,��ʾ����;1,��ʾ����;

void MX_SPI_Send(uint8_t data)
{
	HAL_SPI_Transmit(&hspi1, &data, 1, 1000);
}

void OLED_WR_Byte(u8 dat, u8 cmd)
{
	SPI2_CS_Clr();
	if (cmd == OLED_DATA)
	{
		OLED_DC_H();
		MX_SPI_Send(dat);
	}
	else if (cmd == OLED_CMD)
	{
		OLED_DC_L();
		MX_SPI_Send(dat);
	}
	SPI2_CS_Set();
}

void OLED_Set_Pos(unsigned char x, unsigned char y)
{
	OLED_WR_Byte(0xb0 + y, OLED_CMD); // 0xb0����ҳ��ַ��ָ�y�Ǿ���ҳ�š�

	OLED_WR_Byte((x & 0x0f) | 0x01, OLED_CMD);
	OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
}

void OLED_DrawPixel(u8 x, u8 y, u8 pixel_on)
{

	//    u8 col = x;
	u8 offset = y % 8;
	u8 data = 0;
	data = arr[x][y / 8];
	if (pixel_on == 1)
	{
		data = data | (0x01 << offset);
	}
	else
	{
		data = data & ~(0x01 << offset);
	}

	arr[x][y / 8] = data;
}

void OLED_RefreshPixel(void)
{
	int i = 0;
	int j = 0;
	for (i = 0; i < 8; i++)
	{
		OLED_Set_Pos(0, i);
		for (j = 0; j < 128; j++)
		{
			OLED_WR_Byte(arr[j][i], OLED_DATA);
		}
	}
}

// ����OLED��ʾ
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC����
	OLED_WR_Byte(0X14, OLED_CMD); // DCDC ON
	OLED_WR_Byte(0XAF, OLED_CMD); // DISPLAY ON
}
// �ر�OLED��ʾ
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC����
	OLED_WR_Byte(0X10, OLED_CMD); // DCDC OFF
	OLED_WR_Byte(0XAE, OLED_CMD); // DISPLAY OFF
}
// ��������,������,������Ļ�Ǻ�ɫ��!��û����һ��!!!
void OLED_Clear(void)
{
	u8 i, n;
	for (i = 0; i < 8; i++)
	{
		OLED_WR_Byte(0xb0 + i, OLED_CMD); // ����ҳ��ַ��0~7��
		OLED_WR_Byte(0x00, OLED_CMD);	  // ������ʾλ�á��е͵�ַ
		OLED_WR_Byte(0x10, OLED_CMD);	  // ������ʾλ�á��иߵ�ַ
		for (n = 0; n < 128; n++)
			OLED_WR_Byte(0, OLED_DATA);
	} // ������ʾ
}

// ��ָ��λ����ʾһ���ַ�,���������ַ�
// x:0~127
// y:0~63
// mode:0,������ʾ;1,������ʾ
// size:ѡ������ 16/12

void OLED_ShowChar(u8 x, u8 y, u8 chr)
{
	unsigned char c = 0, i = 0;
	c = chr - ' '; // �õ�ƫ�ƺ���?
	if (x > Max_Column - 1)
	{
		x = 0;
		y = y + 2;
	}
	if (SIZE == 16)
	{
		OLED_Set_Pos(x, y);
		for (i = 0; i < 8; i++)
			OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA);
		OLED_Set_Pos(x, y + 1);
		for (i = 0; i < 8; i++)
			OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA);
	}
	else
	{
		OLED_Set_Pos(x, y + 1);
		for (i = 0; i < 6; i++)
			OLED_WR_Byte(F6x8[c][i], OLED_DATA);
	}
}

// m^n����
u32 oled_pow(u8 m, u8 n)
{
	u32 result = 1;
	while (n--)
		result *= m;
	return result;
}
// ��ʾ2������
// x,y :�������?
// len :���ֵ�λ��
// size:������?
// mode:ģʽ	0,���ģ�?;1,����ģʽ
// num:��ֵ(0~4294967295);

void OLED_ShowNum(u8 x, u8 y, u32 num, u8 len, u8 size)
{
	u8 t, temp;
	u8 enshow = 0;
	for (t = 0; t < len; t++)
	{
		temp = (num / oled_pow(10, len - t - 1)) % 10;
		if (enshow == 0 && t < (len - 1))
		{
			if (temp == 0)
			{
				OLED_ShowChar(x + (size / 2) * t, y, ' ');
				continue;
			}
			else
				enshow = 1;
		}
		OLED_ShowChar(x + (size / 2) * t, y, temp + '0');
	}
}

// ��ʾһ���ַ��Ŵ�
void OLED_ShowString(u8 x, u8 y, u8 *chr)
{
	unsigned char j = 0;
	while (chr[j] != '\0')
	{
		OLED_ShowChar(x, y, chr[j]);
		x += 8;
		if (x > 120)
		{
			x = 0;
			y += 2;
		}
		j++;
	}
}
// ��ʾ����
void OLED_ShowCHinese(u8 x, u8 y, u8 no)
{
	u8 t, adder = 0;
	OLED_Set_Pos(x, y);
	for (t = 0; t < 16; t++)
	{
		OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA);
		adder += 1;
	}
	OLED_Set_Pos(x, y + 1);
	for (t = 0; t < 16; t++)
	{
		OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA);
		adder += 1;
	}
}

/***********������������ʾ��ʾBMPͼƬ128��64��ʼ������(x,y),x�ķ�Χ0��127��yΪҳ�ķ�Χ0��7*****************/
unsigned int j = 0;
unsigned char x, y;

void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[])
{

	for (y = y0; y < y1; y++)
	{
		OLED_Set_Pos(x0, y);
		for (x = x0; x < x1; x++)
		{
			OLED_WR_Byte(BMP[j++], OLED_DATA);
		}
	}
}

void OLED_ShowPIC(u8 pic_x, u8 pic_y, uint8_t pic_w, uint8_t pic_h, unsigned char *BMP)
{
	OLED_Set_Pos(pic_x, pic_y);
	int j, i = 0;
	for (i = 0; i < pic_h; i++)
	{
		OLED_Set_Pos(pic_x, pic_y + i);
		for (j = 0; j < pic_w; j++)
		{
			OLED_WR_Byte(BMP[j + 28 * i], OLED_DATA);
		}
	}
}

void OLED_ShowD(u8 pic_x, u8 pic_y, uint8_t pic_w, uint8_t pic_h, unsigned char *BMP)
{
	OLED_Set_Pos(pic_x, pic_y);
	int j, i = 0;
	for (i = 0; i < pic_h; i++)
	{
		OLED_Set_Pos(pic_x, pic_y + i);
		for (j = 0; j < pic_w; j++)
		{
			OLED_WR_Byte(BMP[j + 8 * i], OLED_DATA);
		}
	}
}

void OLED_ShowBattery(u8 pic_x, u8 pic_y, uint8_t pic_w, uint8_t pic_h, unsigned char *BMP)
{
	OLED_Set_Pos(pic_x, pic_y);
	int j, i = 0;
	for (i = 0; i < pic_h; i++)
	{
		OLED_Set_Pos(pic_x, pic_y + i);
		for (j = 0; j < pic_w; j++)
		{
			OLED_WR_Byte(BMP[j + 36 * i], OLED_DATA);
		}
	}
}

void OLED_ShowBTM(u8 pic_x, u8 pic_y, uint8_t pic_w, uint8_t pic_h, unsigned char *BMP)
{
	OLED_Set_Pos(pic_x, pic_y);
	int j, i = 0;
	for (i = 0; i < pic_h; i++)
	{
		OLED_Set_Pos(pic_x, pic_y + i);
		for (j = 0; j < pic_w; j++)
		{
			OLED_WR_Byte(BMP[j + 36 * i], OLED_DATA);
		}
	}
}

void OLED_CleanNum(u8 pic_x, u8 pic_y, uint8_t pic_w, uint8_t pic_h)
{
	OLED_Set_Pos(pic_x, pic_y);
	int j, i = 0;
	for (i = 0; i < pic_h; i++)
	{
		OLED_Set_Pos(pic_x, pic_y + i);
		for (j = 0; j < pic_w; j++)
		{
			OLED_WR_Byte(0x00, OLED_DATA);
		}
	}
}
void fill_picture(unsigned char fill_Data)
{
	unsigned char m, n;
	for (m = 0; m < 8; m++)
	{
		OLED_WR_Byte(0xb0 + m, 0); // page0-page1
		OLED_WR_Byte(0x00, 0);	   // low column start address
		OLED_WR_Byte(0x10, 0);	   // high column start address
		for (n = 0; n < 128; n++)
		{
			OLED_WR_Byte(fill_Data, 1);
		}
	}
}


void UnShowScream(void)
{
	int j, i = 0;
	for (i = 0; i < 8; i++)
	{
		OLED_Set_Pos(0,i);
		for (j = 0; j < 128; j++)
		{			
			OLED_WR_Byte(0x00, OLED_DATA);
		}
	}
}


// ��ʼ��SSD1306
void OLED_Init(void)
{

	// ��ʼ��res��dc��

	// ��ʼ��res��dc��
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	/* GPIO Ports Clock Enable */
	__HAL_RCC_GPIOB_CLK_ENABLE();

	/*Configure GPIO pin Output Level */
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0 | GPIO_PIN_1, GPIO_PIN_RESET);

	/*Configure GPIO pins : PB0 PB1 */
	GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	OLED_RST_Set();
	HAL_Delay(100);
	OLED_RST_Clr();
	HAL_Delay(200);
	OLED_RST_Set();

	OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel
	OLED_WR_Byte(0x00, OLED_CMD); //---set low column address
	OLED_WR_Byte(0x10, OLED_CMD); //---set high column address
	OLED_WR_Byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register
	OLED_WR_Byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness
	OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping     0xa0���ҷ��� 0xa1����
	OLED_WR_Byte(0xC8, OLED_CMD); // Set COM/Row Scan Direction   0xc0���·��� 0xc8����
	OLED_WR_Byte(0xA6, OLED_CMD); //--set normal display
	OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3f, OLED_CMD); //--1/64 duty
	OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	OLED_WR_Byte(0x00, OLED_CMD); //-not offset
	OLED_WR_Byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
	OLED_WR_Byte(0x80, OLED_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec
	OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period
	OLED_WR_Byte(0xF1, OLED_CMD); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration
	OLED_WR_Byte(0x12, OLED_CMD);
	OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh
	OLED_WR_Byte(0x40, OLED_CMD); // Set VCOM Deselect Level
	OLED_WR_Byte(0x20, OLED_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)
	OLED_WR_Byte(0x02, OLED_CMD); //
	OLED_WR_Byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable
	OLED_WR_Byte(0x14, OLED_CMD); //--set(0x10) disable
	OLED_WR_Byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
	OLED_WR_Byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
	OLED_WR_Byte(0xAF, OLED_CMD); //--turn on oled panel

	OLED_WR_Byte(0xAF, OLED_CMD); /*display ON*/
	OLED_Clear();
	OLED_Set_Pos(0, 0);

	for (int i = 0; i < 128; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			arr[i][j] = 0x0;
		}
	}
}
